/*
 * Copyright (c) 2006-2019, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2017-07-24     Tanek        the first version
 * 2018-11-12     Ernest Chen  modify copyright
 * 2021-06-03     crazt        HK32F030 Porting
 */
 
#include <stdint.h>
#include <rthw.h>
#include <rtthread.h>
#include "hk32f030m.h"


#define _SCB_BASE       (0xE000E010UL)
#define _SYSTICK_CTRL   (*(rt_uint32_t *)(_SCB_BASE + 0x0))
#define _SYSTICK_LOAD   (*(rt_uint32_t *)(_SCB_BASE + 0x4))
#define _SYSTICK_VAL    (*(rt_uint32_t *)(_SCB_BASE + 0x8))
#define _SYSTICK_CALIB  (*(rt_uint32_t *)(_SCB_BASE + 0xC))
#define _SYSTICK_PRI    (*(rt_uint8_t  *)(0xE000ED23UL))

#define  USART1_TX_PORT         GPIOA
#define  USART1_TX_PIN          GPIO_Pin_3
#define  USART1_TX_IO_CLK_EN()  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE)
	
#define  USART1_RX_PORT         GPIOD
#define  USART1_RX_PIN          GPIO_Pin_6
#define  USART1_RX_IO_CLK_EN()  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE)

//static struct rt_semaphore shell_rx_sem;

// Updates the variable SystemCoreClock and must be called 
// whenever the core clock is changed during program execution.
extern void SystemCoreClockUpdate(void);

// Holds the system core clock, which is the system clock 
// frequency supplied to the SysTick timer and the processor 
// core clock.
extern uint32_t SystemCoreClock;

static uint32_t _SysTick_Config(rt_uint32_t ticks)
{
    if ((ticks - 1) > 0xFFFFFF)
    {
        return 1;
    }
    
    _SYSTICK_LOAD = ticks - 1; 
    _SYSTICK_PRI = 0xFF;
    _SYSTICK_VAL  = 0;
    _SYSTICK_CTRL = 0x07;  
    
    return 0;
}

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
#define RT_HEAP_SIZE 1024
static uint32_t rt_heap[RT_HEAP_SIZE];     // heap default size: 4K(1024 * 4)
RT_WEAK void *rt_heap_begin_get(void)
{
    return rt_heap;
}

RT_WEAK void *rt_heap_end_get(void)
{
    return rt_heap + RT_HEAP_SIZE;
}
#endif


static void USART_GPIO_Configurature(void);
static void USART_NVIC_Configurature(void);
static int uart_init(void);
/**
 * This function will initial your board.
 */
void rt_hw_board_init()
{
    /* System Clock Update */
    SystemCoreClockUpdate();
    
    /* System Tick Configuration */
    _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
    
    uart_init();

    /* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif

#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}

void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    rt_tick_increase();

    /* leave interrupt */
    rt_interrupt_leave();
}

static int uart_init(void)
{
   	USART_InitTypeDef m_usart;
	
	USART_GPIO_Configurature();
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	m_usart.USART_BaudRate = 115200;
	m_usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	m_usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	m_usart.USART_Parity = USART_Parity_No;
	m_usart.USART_StopBits = USART_StopBits_1;
	m_usart.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART1, &m_usart);
	USART_Cmd(USART1, ENABLE);
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	
	USART_NVIC_Configurature();

    return 0;
}
//INIT_BOARD_EXPORT(uart_init);

static void USART_GPIO_Configurature(void)
{
	GPIO_InitTypeDef m_gpio;
	
	USART1_TX_IO_CLK_EN();
	USART1_RX_IO_CLK_EN();
	
	m_gpio.GPIO_Mode = GPIO_Mode_AF;
	m_gpio.GPIO_OType = GPIO_OType_PP;
	m_gpio.GPIO_Pin = USART1_TX_PIN;
	m_gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
	m_gpio.GPIO_Speed = GPIO_Speed_10MHz;
	GPIO_Init(USART1_TX_PORT, &m_gpio);
	GPIO_PinAFConfig(USART1_TX_PORT,GPIO_PinSource3,GPIO_AF_1);
	
	m_gpio.GPIO_Pin = USART1_RX_PIN;
	GPIO_Init(USART1_RX_PORT, &m_gpio);
	GPIO_PinAFConfig(USART1_RX_PORT,GPIO_PinSource6,GPIO_AF_1);
}
static void USART_NVIC_Configurature(void)
{
	NVIC_SetPriority(USART1_IRQn,0);
	NVIC_EnableIRQ(USART1_IRQn);
}
// Implement  rt_hw_console_output
void USART1_SendByte(uint8_t ch)
{
	while((USART1->ISR & USART_ISR_TXE) == 0);
	USART1->TDR = ch;
}
void rt_hw_console_output(const char *str)
{
    rt_size_t i = 0, size = 0;
    char a = '\r';

    size = rt_strlen(str);
    for (i = 0; i < size; i++)
    {
        if (*(str + i) == '\n')
        {
            USART1_SendByte((uint8_t)a);
        }
        USART1_SendByte(*(str + i));
    }
}
//char rt_hw_console_getchar(void)
//{
//    int ch = -1;
//    rt_sem_take(&shell_rx_sem, RT_WAITING_FOREVER);
//    ch = USART1->RDR;
//    return ch;
//}
//void USART1_IRQHandler(void)
//{
//    if ((USART1->ISR & USART_ISR_RXNE) != 0)
//    {
//        rt_sem_release(&shell_rx_sem);
//    }
//}

